﻿
/**
 * class that represents a problem 
 */
public class UndirectedGraph
{
    /**
     * Set of actions
     */
    private System.Collections.Generic.List<Edge> mEdges;
    
    /**
     * Set of states
     */
    private System.Collections.Generic.List<Node> mNodes;

    /**
     * Node that represents the initial state 
     */
    private Node mInitialNode;

    /**
     * Node that represents the goal
     */
    private Node mGoal;

    /**
     * default constructor, that creates an empry undirected graph
     */
    public UndirectedGraph()
    {
        mEdges = new System.Collections.Generic.List<Edge>();
        mNodes = new System.Collections.Generic.List<Node>();
        mInitialNode = null;
        mGoal = null;
    }

    /**
     * reset problem
     */
    public void setupProblem(string initialState, string goalState)
    {
        mInitialNode = findNode(initialState);
        mGoal = findNode(goalState);

        if (mInitialNode == null || mGoal == null) { throw new System.Exception("NullPointer"); }

        /** reset all nodes */
        foreach (Node n in mNodes) {
            n.setDepth(int.MaxValue);
            n.setPredecessorEdge(null);
            n.setParent(null);
            n.setPathCost(float.PositiveInfinity);
        }

        /** values for initial state */
        mInitialNode.setDepth(0);
        mInitialNode.setPathCost(0.0f);
    }

    /**
     * Goal test
     */
    public bool isGoal(Node node)
    {
        return (node == mGoal);
    }

    /*
     * Successor function
     */
    public System.Collections.Generic.List<System.Tuple<Edge, Node>> getSuccessors(Node node)
    {
        System.Collections.Generic.List<System.Tuple<Edge, Node>> result = new System.Collections.Generic.List<System.Tuple<Edge, Node>>();
        foreach (Edge e in mEdges) {
            Node adj = e.getAdjacentNode(node);
            /** test, if adjacent node is found and ADDITIONALLY, if adjacent node is parent!! */
            if (adj != null && node.getParent() != adj) {
                /** generate tuple of <ACTION, STATE> */
                System.Tuple<Edge, Node> tuple = new System.Tuple<Edge, Node>(e, adj);
                result.Add(tuple);
            }
        }
        return result;
    }

    /**
     * Find node by state
     */
    public Node findNode(string state)
    {
        foreach (Node n in mNodes) {
            if (n.getState().CompareTo(state) == 0) { return n; }
        }
        return null;
    }

    /**
     * Find edge by given states
     */
    public Edge findEdge(string stateA, string stateB)
    {
        Node nodeA = findNode(stateA);
        Node nodeB = findNode(stateB);

        if (nodeA != null && nodeB != null) {
            foreach (Edge e in mEdges) {
                if (e.getAdjacentNode(nodeA) == nodeB) { return e; }
            }
        }
        return null;
    }
  
    /**
     * Read in graph from file
     */
    public void readInProblem(string fn)
    {
        /** clear old graph */
        mEdges.Clear();
        mNodes.Clear();

        /** open file */
        System.IO.StreamReader streamReader = System.IO.File.OpenText(fn);
        
        /** read in file */
        string str = streamReader.ReadLine();
        while (str != null) {
            string[] splitString = str.Split();
            if (splitString.Length < 3) { break; }
            
            string nameNodeA = splitString[0];
            string nameNodeB = splitString[1];
            float costs = int.Parse(splitString[2]);

            /** get nodes, if existent */
            Node nodeA = findNode(nameNodeA);
            Node nodeB = findNode(nameNodeB);
            
            /** create nodes and add, if necessary */
            if (nodeA == null) {
                nodeA = new Node(nameNodeA);
                mNodes.Add(nodeA);
            }
            if (nodeB == null) {
                nodeB = new Node(nameNodeB);
                mNodes.Add(nodeB);
            }


            /** get edge, if existent */
            Edge edge = findEdge(nameNodeA, nameNodeB);

            /** create edge and add, if necessary */
            if (edge == null) {
                edge = new Edge(costs, nodeA, nodeB);
                mEdges.Add(edge);
            }

            /** read next line */
            str = streamReader.ReadLine();
        }
        streamReader.Close();
    }
           

} // class UndirectedGraph